/*
 * Copyright (c) 2024 endless-sky
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#ifndef PERIPHERAL_DEVICE_MONITOR_H__
#define PERIPHERAL_DEVICE_MONITOR_H__

#include <functional>
#include <memory>
#include <thread>
#include <atomic>
#include <string>
#include <vector>
#include <map>
#include <mutex>

namespace El {
namespace Peripheral {

/**
 * @brief 设备事件类型
 */
enum class DeviceEvent {
    ADDED,      // 设备插入
    REMOVED     // 设备拔出
};

/**
 * @brief 设备信息结构
 */
struct DeviceInfo {
    std::string subsystem;  // 子系统 (如 "block", "sound")
    std::string devnode;    // 设备节点 (如 "/dev/sda")
    std::string sysname;    // 系统名称 (如 "sda")
    std::string syspath;    // 系统路径 (如 "/sys/devices/...")
    std::string devtype;    // 设备类型 (如 "disk")

    // 属性键值对 (如 "ID_BUS"="usb", "ID_MODEL"="...")
    std::map<std::string, std::string> properties;
};

/**
 * @brief 设备枚举回调函数类型
 * @param deviceInfo 设备信息
 */
using DeviceEnumerateCallback = std::function<void(const DeviceInfo& deviceInfo)>;

/**
 * @brief 设备事件回调函数类型
 * @param event 事件类型
 * @param subsystem 子系统名称 (如 "sound", "video", "block" 等)
 * @param devnode 设备节点路径 (如 "/dev/snd/pcmC1D0c", "/dev/sda1")
 * @param sysname 系统名称 (如 "pcmC1D0c", "sda1")
 */
using DeviceEventCallback = std::function<void(
    DeviceEvent event,
    const std::string& subsystem,
    const std::string& devnode,
    const std::string& sysname
)>;

/**
 * @brief 设备热插拔监控器
 *
 * 通用的设备热插拔检测模块，支持监控多种设备类型(USB、存储、网络等)。
 * 可被不同的外设模块复用，实现设备热插拔感知。
 */
class DeviceMonitor {
public:
    /**
     * @brief 获取单例实例
     */
    static DeviceMonitor& GetInstance();

    /**
     * @brief 启动/配置设备监控
     * @param subsystems 要监控的子系统列表 (如 {"sound", "video", "block"})
     *
     * 行为说明：
     * - 若未运行，则按提供的列表启动；
     * - 若已运行，则与现有列表取并集，必要时重启监控线程以生效；
     * - 传入空列表表示监听所有子系统（不添加udev过滤）。
     *
     * @return true=成功, false=失败
     */
    bool Start(const std::vector<std::string>& subsystems = {"sound"});

    /**
     * @brief 停止设备监控
     */
    void Stop();

    /**
     * @brief 注册设备事件回调
     * @param subsystem 子系统名称 (为空表示监听所有)
     * @param callback 回调函数
     * @return 回调句柄 (用于注销)
     */
    int32_t RegisterCallback(const std::string& subsystem, DeviceEventCallback callback);

    /**
     * @brief 注销设备事件回调
     * @param handle 回调句柄
     */
    void UnregisterCallback(int32_t handle);

    /**
     * @brief 枚举当前已存在的设备
     * @param subsystem 子系统名称 (如 "block")
     * @param devtype 设备类型过滤 (可选，如 "disk")
     * @param callback 枚举回调，每发现一个设备调用一次
     * @return true=成功, false=失败
     */
    bool EnumerateDevices(const std::string& subsystem,
                          const std::string& devtype,
                          DeviceEnumerateCallback callback);

    /**
     * @brief 检查监控器是否运行中
     */
    bool IsRunning() const { return running_; }

    // 禁止拷贝和赋值
    DeviceMonitor(const DeviceMonitor&) = delete;
    DeviceMonitor& operator=(const DeviceMonitor&) = delete;

private:
    DeviceMonitor();
    ~DeviceMonitor();

    /**
     * @brief udev监听线程函数
     */
    void MonitorThread();

    /**
     * @brief 通知所有注册的回调
     */
    void NotifyCallbacks(DeviceEvent event,
                        const std::string& subsystem,
                        const std::string& devnode,
                        const std::string& sysname);

    struct CallbackInfo {
        int32_t handle;
        std::string subsystem;  // 空字符串表示监听所有子系统
        DeviceEventCallback callback;
    };

    std::atomic<bool> running_{false};
    std::unique_ptr<std::thread> monitorThread_;
    std::vector<std::string> subsystems_;
    // 用于串行化Start/Stop/重启，避免竞争
    mutable std::mutex startStopMutex_;

    std::mutex callbacksMutex_;
    std::vector<CallbackInfo> callbacks_;
    int32_t nextHandle_{1};
};

} // namespace Peripheral
} // namespace El

#endif // PERIPHERAL_DEVICE_MONITOR_H__
